package com.calm.editor.point;  
  
import java.io.StringReader;

import javax.annotation.Resource;
import javax.persistence.EntityManagerFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.orm.jpa.EntityManagerHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import com.calm.editor.api.CacheHandler;
import com.calm.editor.api.CacheService;
import com.calm.editor.servlet.Parameter;
import com.calm.editor.servlet.Result;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.google.gson.stream.JsonReader;
  
public class WebsocketEndPoint extends TextWebSocketHandler {
	private static final Logger LOGGER=LoggerFactory.getLogger(WebsocketEndPoint.class);
	@Resource
	private ApplicationContext context;
	@Resource
	private EntityManagerFactory emf;
	@Resource
	private CacheService<CacheBean> cacheService;
	@Resource
	private CacheHandler<Parameter,CacheBean> cacheHandler;
	
	private Gson gson = new GsonBuilder().addSerializationExclusionStrategy(new ExclusionStrategy() {
		
		@Override
		public boolean shouldSkipField(FieldAttributes f) {
			Expose annotation = f.getAnnotation(Expose.class);
			if(annotation==null){
				return false;
			}
			return !annotation.serialize();
		}
		
		@Override
		public boolean shouldSkipClass(Class<?> clazz) {
			return false;
		}
	}).create();
    @Override  
    protected void handleTextMessage(WebSocketSession session,  
            TextMessage message) throws Exception {
    	boolean participate = false;
    	if (TransactionSynchronizationManager.hasResource(emf)) {
			participate = true;
		}else{
			Object resource = TransactionSynchronizationManager.getResource(emf);
	    	if(resource==null){
	    		EntityManagerHolder emHolder = new EntityManagerHolder(emf.createEntityManager());
	    		TransactionSynchronizationManager.bindResource(emf, emHolder);
	    	}
		}
    	try{
    		JsonReader aa = new JsonReader(new StringReader(message.getPayload()));
    		aa.setLenient(true);
    		Parameter para = gson.fromJson(aa, Parameter.class);
    		final Result<Object> result=new Result<>();
    		String json = null;
    		CacheBean cacheBean=cacheService.handler(para,cacheHandler);
    		
    		try {
    			Class<?>[] parameterTypes = cacheBean.getParameterTypes();
				int length=parameterTypes.length;
				Object[] args=new Object[length];
				for(int i=0;i<length;i++){
					Class<?> type = parameterTypes[i];
					if(type.equals(Result.class)){
						args[i]=result;
					}else{
						Object fromJson = gson.fromJson(para.getData(), parameterTypes[0]);
						args[i]=fromJson;
					}
				}
				result.setEvents(cacheBean.getEvents());
				Object invoke=cacheBean.getTargetMethod().invoke(cacheBean.getTargetBean(), args);
				result.setData(invoke);
				json = gson.toJson(result);
    		} catch (Throwable e) {
    			LOGGER.error(e.getMessage(), e);
    			result.setMessage(e.getMessage());
    			result.setStatus(Result.STATUS_ERROR);
    			result.setData(null);
    			json = gson.toJson(result);
    		}
			session.sendMessage(new TextMessage(json));
    	}finally{
    		if (!participate) {
				EntityManagerHolder emHolder = (EntityManagerHolder)
						TransactionSynchronizationManager.unbindResource(emf);
				EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
			}
    	}
    	
    }  
}  